# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: jshin, leon

import datetime

from coin.exchange.base.order_gateway import OrderSide, OrderType
from coin.exchange.okex_futures.types import OkexFuturesOrderSide
from coin.proto.coin_order_gateway_pb2 import OrderEvent
import coin.proto.coin_order_enums_pb2 as coin_order


def okex_futures_to_proto_order_side(order_side: OkexFuturesOrderSide):
  assert isinstance(order_side, OkexFuturesOrderSide), order_side
  if order_side == OkexFuturesOrderSide.BUY_OPEN:
    order_side = coin_order.BUY_OPEN_ORDER
  elif order_side == OkexFuturesOrderSide.BUY_CLOSE:
    order_side = coin_order.BUY_CLOSE_ORDER
  elif order_side == OkexFuturesOrderSide.SELL_OPEN:
    order_side = coin_order.SELL_OPEN_ORDER
  elif order_side == OkexFuturesOrderSide.SELL_CLOSE:
    order_side = coin_order.SELL_CLOSE_ORDER
  else:
    raise ValueError(order_side)
  return order_side


def _to_proto_order_side(order_side: OrderSide):
  assert isinstance(order_side, OrderSide), order_side
  if order_side == OrderSide.BUY:
    order_side = coin_order.BUY_ORDER
  elif order_side == OrderSide.SELL:
    order_side = coin_order.SELL_ORDER
  else:
    raise ValueError(order_side)
  return order_side


def to_proto_order_side(order_side):
  try:
    return _to_proto_order_side(order_side)
  except (AssertionError, ValueError):
    pass

  try:
    return okex_futures_to_proto_order_side(order_side)
  except (AssertionError, ValueError):
    pass

  raise ValueError('Invalid order_side: %s' % order_side)


def to_proto_order_type(order_type: OrderType):
  if order_type == OrderType.LIMIT:
    order_type = coin_order.DAY_LIMIT_ORDER
  elif order_type == OrderType.IOC:
    order_type = coin_order.IOC_LIMIT_ORDER
  else:
    raise ValueError(order_type)
  return order_type


def prepare_builder(BuilderType, ProtoType, timestamp, id, exchange_type, symbol):
  if ProtoType is not None:
    builder = BuilderType(ProtoType, timestamp, id)
  else:
    builder = BuilderType(timestamp, id)
  builder.set_symbol(exchange_type, symbol)
  return builder


class BaseOrderEventBuilder(object):
  def __init__(self, timestamp, order_event_id):
    ts_datetime = datetime.datetime.utcfromtimestamp(timestamp / 1e9)
    trading_date = int(ts_datetime.strftime("%Y%m%d"))
    self.oe = OrderEvent(order_event_id=order_event_id,
                         event_time=timestamp,
                         logger_write_time=timestamp,
                         trading_date=trading_date,
                         is_live=True)

  def set_symbol(self, exchange_type, symbol):
    self.oe.exchange_type = exchange_type
    self.oe.symbol = symbol

  def set_order_info(self, internal_order_id, order_price, order_qty, order_side, order_type):
    self.oe.internal_order_id = internal_order_id
    self.oe.order_price = order_price
    self.oe.order_qty = order_qty
    self.oe.order_side = order_side
    self.oe.order_type = order_type

  def set_order(self, order, external_order_id):
    internal_order_id = str(order.order_id)
    order_price = order.price
    order_qty = order.qty
    order_side = to_proto_order_side(order.order_side)
    order_type = to_proto_order_type(order.order_type)
    self.set_order_info(internal_order_id, order_price, order_qty, order_side, order_type)
    self.oe.external_order_id = external_order_id

  def set_fill(self,
               fill_price,
               fill_qty,
               *,
               fill_type=None,
               guess_fill_type=None,
               fill_source=None):
    self.oe.fill_price = fill_price
    self.oe.fill_qty = fill_qty
    if fill_type is not None:
      self.oe.fill_type = fill_type
    if guess_fill_type is not None:
      self.oe.guess_fill_type = guess_fill_type
    if fill_source is not None:
      self.oe.fill_source = fill_source

  def set_state(self, order_event_type, order_state, order_event_source):
    self.oe.type = order_event_type
    self.oe.order_state = order_state
    self.oe.order_event_source = order_event_source


class BaseRequestBuilder(object):
  def __init__(self, Type, timestamp, request_id):
    self.request = Type(request_id=request_id)

  def set_symbol(self, exchange_type, symbol):
    self.request.exchange_type = exchange_type
    self.request.symbol = symbol

  def set_order_info(self, internal_order_id, order_price, order_qty, order_side, order_type):
    self.request.internal_order_id = internal_order_id
    self.request.order_price = order_price
    self.request.order_qty = order_qty
    self.request.order_side = order_side
    self.request.order_type = order_type


class BaseResponseBuilder(object):
  def __init__(self, Type, timestamp, response_id):
    self.response = Type()

  def set_symbol(self, exchange_type, symbol):
    self.response.exchange_type = exchange_type
    self.response.symbol = symbol
